/*
 * Copyright (C) 2012 Nicolas BARBOTIN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "GCUtils.h"
#include "GCEADialog.h"
#include "GCColorButton.h"

GCProcess::GCProcess(QString exe, QString path, QString b, QWidget *p) :
    QDialog(p)
{
    vbl = new QVBoxLayout();
    log = new QTextEdit(this);
    closeBtn = new QPushButton(tr("Fermer"), this);
    bin = b;
    out = path + "/bin";
    compOk = false;

    closeBtn->setDisabled(true);
    log->setReadOnly(true);
    log->setStyleSheet("background-color: black; color: white;");
    vbl->addWidget(log);
    vbl->addWidget(closeBtn);
    setLayout(vbl);

    setWindowTitle(tr("GameGenerator"));
    setWindowIcon(QIcon(":/icon.png"));

    make = new QProcess(this);
    make->setWorkingDirectory(path);

    connect(closeBtn, SIGNAL(clicked()), this, SLOT(end()));
    connect(make, SIGNAL(finished(int)), this, SLOT(canClose(int)));
    connect(make, SIGNAL(readyReadStandardOutput()), this, SLOT(incomming()));

    make->start(exe, QIODevice::ReadOnly);
}

void GCProcess::canClose(int ec)
{
    QString msg = "<span style=\"color: ";
    compOk = (ec == 0);

    if(compOk)
        msg += "#00FF00";
    else
        msg += "red";

    msg += ";\">" + tr("Le processus a ete termine avec le code %1 !").arg(ec) + "</span>";
    log->append(msg);

    if(compOk) {
        copy(bin + "/libgcc_s_dw2-1.dll", out);
        copy(bin + "/mingwm10.dll", out);
        copy(bin + "/openal32.dll", out);
        copy(bin + "/libsndfile-1.dll", out);
        copy(bin + "/sfml-audio-2.dll", out);
        copy(bin + "/sfml-graphics-2.dll", out);
        copy(bin + "/sfml-network-2.dll", out);
        copy(bin + "/sfml-system-2.dll", out);
        copy(bin + "/sfml-window-2.dll", out);
        copy(bin + "/GameGenLib.dll", out);

        log->append(tr("<span style=\"color: #00FF00;\">Appuyez sur Fermer pour lancer votre jeu.</span>"));
    }

    closeBtn->setEnabled(true);
}

void GCProcess::incomming()
{
    log->setText(log->document()->toPlainText() + make->readAllStandardOutput());
}

void GCProcess::end()
{
    if(compOk)
        emit ended();

    accept();
}

void GCProcess::copy(QString in, QString out)
{
    if(QFile::exists(out))
        QFile::remove(out);

    QString name = in.replace("\\", "/");
    name = in.right(in.size() - in.lastIndexOf("/") - 1);

    QString message = tr("Copie de %1... ").arg(name);
    if(QFile::copy(in, out + "/" + name))
        message += tr("OK !");
    else
        message += tr("Erreur !");

    log->append(message);
}

int GCUtils::OpenEventSelectDialog(GCDataReader *dr) {
    GCEADialog *dialog = new GCEADialog(dr, true);
    if(dialog->exec())
        return dialog->getClicked();

    return -1;
}

QIcon GCUtils::getIconByCat(int cat, GCDataReader *dr)
{
    return QIcon(dr->getCategory(cat).icon);
}

QIcon GCUtils::getIconByACat(int cat, GCDataReader *dr)
{
    return QIcon(dr->getACategory(cat).icon);
}

int GCUtils::OpenActionSelectDialog(GCDataReader *dr) {
    GCEADialog *dialog = new GCEADialog(dr, false);
    if(dialog->exec())
        return dialog->getClicked();

    return -1;
}

void GCUtils::OpenParamSelectDialog(GCProject *p, bool isAction, int cat, GCDataReader *dr, int oid, int eid, int aid)
{
    if(isAction && aid < 0)
        return;

    QDialog *apSel = new QDialog();
    QFormLayout *layout = new QFormLayout();
    QDialogButtonBox *dbb = new QDialogButtonBox();
    dbb->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);

    QList<QWidget*> curWidgets;
    QList<QToolButton*> toText;
    QList<QLineEdit*> asText;

    int pCount = 0;
    if(isAction)
        pCount = p->getObjects(oid).events[eid].actions[aid].params.count();
    else
        pCount = p->getObjects(oid).events[eid].params.count();

    for(int i = 0; i < pCount; i++) {
        QVariant cValue;
        EnumParamType cPT;
        QString cName;
        if(isAction) {
            cValue = p->getObjects(oid).events[eid].actions[aid].params[i].dat;
            cPT = dr->getAction(cat).actionParams[i].paramType;
            cName = dr->getAction(cat).actionParams[i].paramName;
        } else {
            cValue = p->getObjects(oid).events[eid].params[i].dat;
            cPT = dr->getEvent(cat).eventParams[i].paramType;
            cName = dr->getEvent(cat).eventParams[i].paramName;
        }

        QWidget *widget;
        bool typeFound = false;

        if(cPT == PT_BOOL) {
            typeFound = true;
            QCheckBox *chkBx = new QCheckBox();
            chkBx->setChecked(cValue.toBool());
            widget = chkBx;
        } else if(cPT == PT_INT) {
            typeFound = true;
            QSpinBox *spBx = new QSpinBox();
            spBx->setMaximum(9999999);
            spBx->setValue(cValue.toInt());
            widget = spBx;
        } else if(cPT == PT_STRING) {
            typeFound = true;
            QLineEdit *le = new QLineEdit();
            le->setMaxLength(9999);

            if(!cValue.toString().isNull() && !cValue.toString().isEmpty())
                le->setText(cValue.toString());

            widget = le;
        } else if(cPT == PT_FLOAT) {
            typeFound = true;
            QDoubleSpinBox *dsb = new QDoubleSpinBox();
            dsb->setMaximum(9999999);
            dsb->setValue(cValue.toFloat());
            widget = dsb;
        } else if(cPT == PT_COMBO) {
            typeFound = true;
            QComboBox *cb = new QComboBox();

            QString ud = "";
            if(isAction)
                ud = dr->getAction(cat).actionParams[i].userData;
            else
                ud = dr->getEvent(cat).eventParams[i].userData;

            QStringList items = ud.split(";");
            for(int j = 0; j < items.count(); j++) {
                QStringList datas = items[j].split(":");
                if(datas.count() != 2) {
                    qDebug() << "Combo parse error at " << j;
                    return;
                }


                cb->addItem(datas[0], QVariant(datas[1]));
            }

            QString data = cValue.toString();
            if(!data.isNull() && !data.isEmpty()) {
                for(int j = 0; j < items.count(); j++) {
                    QStringList codeValue = items[j].split(":");
                    if(codeValue.count() != 2) {
                        qDebug() << "Combo reload error at " << j;
                        return;
                    }

                    if(data == items[j].split(":")[1])
                        cb->setCurrentIndex(j);
                }
            }

            widget = cb;
        } else if(cPT == PT_COLOR) {
            typeFound = true;
            GCColorButton *colb = new GCColorButton();
            colb->setColor(cValue.value<QColor>());
            widget = colb;
        } else if(cPT == PT_SPRITE) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countSprites(); j++)
                cb->addItem(p->getSprites(j).name);

            widget = cb;
        } else if(cPT == PT_MUSIC) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countSounds(); j++)
                cb->addItem(p->getSounds(j).name);

            widget = cb;
        } else if(cPT == PT_OBJECT) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countObjects(); j++)
                cb->addItem(p->getObjects(j).name);

            cb->setCurrentIndex(cValue.toInt());
            widget = cb;
        } else if(cPT == PT_SCRIPT) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countScripts(); j++)
                cb->addItem(p->getScripts(j).name);

            cb->setCurrentIndex(cValue.toInt());
            widget = cb;
        } else if(cPT == PT_BACKGROUND) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countBackgrounds(); j++)
                cb->addItem(p->getBackgrounds(j).name);

            cb->setCurrentIndex(cValue.toInt());
            widget = cb;
        } else if(cPT == PT_ROOM) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countRooms(); j++)
                cb->addItem(p->getRooms(j).name);

            cb->setCurrentIndex(cValue.toInt());
            widget = cb;
        } else if(cPT == PT_FONT) {
            typeFound = true;

            QComboBox *cb = new QComboBox();
            for(int j = 0; j < p->countFonts(); j++) {
                QString fntName = p->getFonts(j).replace("\\", "/");
                cb->addItem(fntName.right(fntName.size() - fntName.lastIndexOf("/") - 1));
            }

            cb->setCurrentIndex(cValue.toInt());
            widget = cb;
        }

        if(!typeFound)
            return;

        asText << new QLineEdit();
        asText.last()->setHidden(true);
        QToolButton *qtb = new QToolButton();
        qtb->setText("<>");
        qtb->setCheckable(true);

        connect(qtb, SIGNAL(toggled(bool)), asText.last(), SLOT(setShown(bool)));
        connect(qtb, SIGNAL(toggled(bool)), widget, SLOT(setHidden(bool)));

        if(isAction) {
            if(p->getObjects(oid).events[eid].actions[aid].params[i].isText) {
                qtb->setChecked(true);
                asText.last()->setText(p->getObjects(oid).events[eid].actions[aid].params[i].dat.toString());
            }
        } else {
            if(p->getObjects(oid).events[eid].params[i].isText) {
                qtb->setChecked(true);
                asText.last()->setText(p->getObjects(oid).events[eid].params[i].dat.toString());
            }
        }

        QHBoxLayout *hbl = new QHBoxLayout();
        hbl->addWidget(widget);
        hbl->addWidget(asText.last());
        hbl->addWidget(qtb);
        layout->addRow(cName, hbl);
        toText << qtb;

        curWidgets << widget;
    }

    layout->addWidget(dbb);
    apSel->setLayout(layout);
    apSel->setWindowTitle(tr("GameGenerator"));
    connect(dbb, SIGNAL(accepted()), apSel, SLOT(accept()));
    connect(dbb, SIGNAL(rejected()), apSel, SLOT(reject()));

    if(apSel->exec()) {
        for(int i = 0; i < curWidgets.count(); i++) {
            EnumParamType cPT;
            if(isAction)
                cPT = dr->getAction(cat).actionParams[i].paramType;
            else
                cPT = dr->getEvent(cat).eventParams[i].paramType;

            if(asText[i]->isHidden()) {
                if(isAction)
                    p->getAParam(oid, eid, aid, i)->isText = false;
                else
                    p->getEParam(oid, eid, i)->isText = false;

                if(cPT == PT_BOOL) {
                    QCheckBox *chkBx = static_cast<QCheckBox*>(curWidgets[i]);
                    SetDatas(p, isAction, chkBx->isChecked(), i, oid, eid, aid);
                } else if(cPT == PT_INT) {
                    QSpinBox *spinBx = static_cast<QSpinBox*>(curWidgets[i]);
                    SetDatas(p, isAction, spinBx->value(), i, oid, eid, aid);
                } else if(cPT == PT_FLOAT) {
                    QDoubleSpinBox *spinBx = static_cast<QDoubleSpinBox*>(curWidgets[i]);
                    SetDatas(p, isAction, spinBx->value(), i, oid, eid, aid);
                } else if(cPT == PT_STRING) {
                    QLineEdit *lineEdt = static_cast<QLineEdit*>(curWidgets[i]);
                    SetDatas(p, isAction, lineEdt->text(), i, oid, eid, aid);
                } else if(cPT == PT_COMBO) {
                    QComboBox *objCmb = static_cast<QComboBox*>(curWidgets[i]);
                    SetDatas(p, isAction, objCmb->itemData(objCmb->currentIndex(), Qt::UserRole), i, oid, eid, aid);
                } else if(cPT == PT_COLOR) {
                    GCColorButton *cBtn = static_cast<GCColorButton*>(curWidgets[i]);
                    SetDatas(p, isAction, cBtn->getColor(), i, oid, eid, aid);
                } else if(cPT == PT_SPRITE || cPT == PT_MUSIC || cPT == PT_OBJECT || cPT == PT_SCRIPT || cPT == PT_BACKGROUND || cPT == PT_ROOM || cPT == PT_FONT) {
                    QComboBox *objCmb = static_cast<QComboBox*>(curWidgets[i]);
                    SetDatas(p, isAction, objCmb->currentIndex(), i, oid, eid, aid);
                }
            } else {
                if(isAction)
                    p->getAParam(oid, eid, aid, i)->isText = true;
                else
                    p->getEParam(oid, eid, i)->isText = true;

                SetDatas(p, isAction, asText[i]->text(), i, oid, eid, aid);
            }
        }
    }

    for(int i = 0; i < pCount; i++) {
        curWidgets[i]->deleteLater();
        asText[i]->deleteLater();
        toText[i]->deleteLater();
    }
    toText.clear();
    curWidgets.clear();
    asText.clear();
}

void GCUtils::SetDatas(GCProject *p, bool isAction, QVariant v, int cat, int oid, int eid, int aid)
{
    if(isAction) {
        if(aid < 0)
            return;

        p->getAParam(oid, eid, aid, cat)->dat = v;
    } else
        p->getEParam(oid, eid, cat)->dat = v;
}
